package com.px.auth.config;

import com.px.auth.security.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class ApiSecurityConfig {
    public static final String JWT_SIGNER_STR = "las$#@^kjdf88ljf7032#(*9ds90839045(%&";
    public static final String HEADER = "Authorization";
    public static final long EXPIRE_SECONDS = 172800;
    public static final String TOKEN_CHECK_URL = "/token_check";

    public static final String LOGIN_URL = "/login";
    public static final String LOGOUT_URL = "/logout";

    @Autowired
    private TokenService tokenService;

    @Autowired
    private AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;

    @Autowired
    private AjaxAuthenticationSuccessHandler ajaxAuthenticationSuccessHandler;

    @Configuration
    @Order(1)
    class PreSecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(AuthenticationManagerBuilder auth) {
            auth.authenticationProvider(new TokenAuthenticationProvider(tokenService));
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .requestMatchers().antMatchers(TOKEN_CHECK_URL, LOGOUT_URL)
                    .and().authorizeRequests().antMatchers(TOKEN_CHECK_URL).authenticated()
                    .and()
                    .addFilterBefore(new AuthExceptionFilter(), BasicAuthenticationFilter.class)
                    .addFilterAfter(new TokenAuthenticationFilter(),
                            BasicAuthenticationFilter.class)
                    .addFilterAfter(new RespExceptionFilter(), ExceptionTranslationFilter.class)
                    .authorizeRequests().and()
                    .logout().logoutUrl(LOGOUT_URL).permitAll().logoutSuccessHandler(ajaxLogoutSuccessHandler)
                    .and()
                    .csrf()
                    .disable()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        }
    }

    @Configuration
    class InOutSecurityConfig extends WebSecurityConfigurerAdapter {

        @Autowired
        @Qualifier("VUserDetailService")
        private UserDetailsService vUserDetailService;

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(vUserDetailService).passwordEncoder(new BCryptPasswordEncoder());
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .requestMatchers().antMatchers("/oauth/**", LOGIN_URL)
                    .and()
                    .addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                    .authorizeRequests().antMatchers("/oauth/**").authenticated()
                    .and()
                    .csrf().disable()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        }

        private JsonAuthenticationFilter authenticationFilter() throws Exception {
            JsonAuthenticationFilter filter = new JsonAuthenticationFilter();
            filter.setAuthenticationManager(authenticationManager());
            filter.setAuthenticationSuccessHandler(ajaxAuthenticationSuccessHandler);
            filter.setAuthenticationFailureHandler(new AjaxAuthenticationFailureHandler());
            filter.setFilterProcessesUrl(LOGIN_URL);
            return filter;
        }
    }
}
